package tresp.bthreads;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Logger;

import robocode.BattleEndedEvent;
import robocode.BulletMissedEvent;
import robocode.DeathEvent;
import robocode.HitRobotEvent;
import robocode.RobotDeathEvent;
import robocode.RoundEndedEvent;
import robocode.ScannedRobotEvent;
import tresp.coordinator.ICoordinator;
import tresp.utils.BThreadVote;
import tresp.utils.EnemyTank;
import tresp.utils.ITankInfo;
import tresp.utils.logging.MyLogger;


/**
 * <b>PatternMatchingTargeting</b>
 * 
 * 
 * 
 * @author <font color="blue">Maxim Kirilov</font>
 *
 */
public class PatternMatchingTargeting extends BThread {

    private static Logger logger = MyLogger.getLogger( PatternMatchingTargeting.class );
    
    /**Holds data about enemies*/
    private Map<String, EnemyTank> enemyCache;    
    
    
    private ITankInfo tankInfo;
    
    private long lastFireTime;
    
    private Lock synchronizationLock;
    
    
    private AtomicReference<ScannedRobotEvent>  lastScannedRobotEvent;
    
    
    public PatternMatchingTargeting(ICoordinator<BThreadVote> coordinator) {
	super(coordinator);
	logger.info("Pattern Matching Targeting B-Thread created successfully");
	enemyCache = new HashMap<String, EnemyTank>();
	tankInfo = coordinator.getTankInfo();
	synchronizationLock = new ReentrantLock( true );
	lastScannedRobotEvent = new AtomicReference<ScannedRobotEvent>();
    }

    @Override
    public void vote() {
	
	ScannedRobotEvent enemy = lastScannedRobotEvent.getAndSet( null );

	if ( enemy != null && !tankInfo.isTeammate( enemy.getName() )){
	    double targetBearingRadians = enemy.getBearingRadians() + tankInfo.getHeadingRadians();
	    BThreadVote vote = createBThreadVote(BThreadType.TURN_RADAR_RIGHT_RADIANS, 
		    0, Math.sin(targetBearingRadians - tankInfo.getRadarHeadingRadians()) * 1.5D);
	    
	    int voteOrder = 10;
	    vote.setWeight( weight + voteOrder );
	    coordinator.vote( vote );
	    voteOrder--;
	    EnemyTank enemyTank = enemyCache.get( enemy.getName() );
	    
	    List<BThreadVote> lRecommendations = enemyTank.recommend(enemy, tankInfo, enemyTank.updateEnemy(enemy, tankInfo));
	    BThreadVote v = lRecommendations.get(0);
	    v.setWeight( weight + voteOrder);
	    voteOrder--;
	    coordinator.vote( v );	
	    if (lRecommendations.size() == 2 ){
		if (System.currentTimeMillis() - lastFireTime > 500 || enemy.getDistance() < 40)
		lastFireTime = System.currentTimeMillis();
		v = lRecommendations.get(1);
		v.setWeight( weight + voteOrder);
		voteOrder--;
		coordinator.vote( v );
	    }
		
	    
	    /*
	    for (BThreadVote v : enemyTank.recommend(enemy, tankInfo, enemyTank.updateEnemy(enemy, tankInfo))){
		v.setWeight( weight + voteOrder);
		voteOrder--;
		coordinator.vote( v );	
	    }
	    */
	}else{ 	
	    BThreadVote vote = createBThreadVote(BThreadType.TURN_RADAR_LEFT_DEGREES, weight, 45D);
	    coordinator.vote( vote );
	}
    }
    
    
    
    @Override
    public void onScannedRobot(ScannedRobotEvent e){
	
	EnemyTank enemyTank = enemyCache.get( e.getName() );
	
	if ( enemyTank == null){
	    synchronizationLock.lock();
	    if ( enemyTank == null){
		enemyTank = new EnemyTank( e.getName() );
		enemyTank.startPatternAnalyzer();
		enemyCache.put( e.getName() , enemyTank);
	    }
	    synchronizationLock.unlock();
	}
	enemyTank.updateEnemy(e, tankInfo);
	lastScannedRobotEvent.set(e);
 
    }
    
    
    @Override
    public void onHitRobot(HitRobotEvent e){
	super.onHitRobot(e);
	
	EnemyTank enemyTank = enemyCache.get( e.getName() );
	if ( enemyTank != null){
	    enemyTank.updateHitCounter();
	}
	
    }
    
    @Override
    public void onBulletMissed(BulletMissedEvent event){
	super.onBulletMissed(event);
    }
    
    
    
    @Override
    public void onRobotDeath(RobotDeathEvent event){
	super.onRobotDeath(event);
	//Stop the pattern Analyzer
	EnemyTank enemyTank = enemyCache.get( event.getName() );
	if ( enemyTank != null && enemyTank.isPatternAnalyzerActive() ){
	    enemyTank.stopPatternAnalyzer();
	}
    }
    
    
    @Override
    public void onDeath(DeathEvent event){
	super.onDeath(event);
	stopPatternAnalyzation();
    }
    
    @Override
    public void onBattleEnded(BattleEndedEvent event){
	super.onBattleEnded(event);
	stopPatternAnalyzation();
    }
    
    
    public void onRoundEnded(RoundEndedEvent event){
	super.onRoundEnded(event);
	stopPatternAnalyzation();
    }

    
    private void stopPatternAnalyzation() {
	for (EnemyTank enemyTank : enemyCache.values()){
	    if ( enemyTank.isPatternAnalyzerActive() ){
		enemyTank.stopPatternAnalyzer();
	    }
	}
    }

    @Override
    public String getName() {
	return "PatternMatchingTargeting";
    }
}
